home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 07 - 1991 / 07.10 Oct 91 / Window Menubar Source ƒ / wBMWindSubs.p < prev    next >
Encoding:
Text File  |  1991-07-25  |  13.9 KB  |  558 lines  |  [TEXT/PJMM]

  1. { ******************************************************** }
  2. { "wBMWindSubs.p"                                          }
  3. {                                                          }
  4. { by John A. Love, III [ Washington Apple Pi Users' Group] }
  5. {                                                          }
  6. { using Symantec's "THINK Lightspeed Pascal", v 3.02       }
  7. {                                                          }
  8. { ******************************************************** }
  9.  
  10.  
  11. UNIT wBMWindSubs;
  12.  
  13. INTERFACE
  14.  
  15.     USES
  16.         Quickdraw, Palettes, wBMInterface, wBMGlobals, wBMMiscSubs, wBMScrollSubs, wBarMenuProc, wBMBalloons;
  17.  
  18.  
  19.     FUNCTION InitWindowStorage: allWSHdl;
  20.     PROCEDURE CalcWindowRect (window: WindowPtr; VAR r: Rect);
  21.     PROCEDURE DisplayWindow (window: WindowPtr; TLPR: Point);
  22.     FUNCTION DoNewWindow (windowID, wMBARID: INTEGER; VAR offset: Point): BOOLEAN;
  23.     PROCEDURE CloseOurWindow (window: WindowPtr);
  24.     PROCEDURE DoCloseAll;
  25.     PROCEDURE UncheckOldItem (windMenu: MenuHandle);
  26. { ----- Thanks to Scott Knaster's "Macintosh Programming Secrets" ----- }
  27.     PROCEDURE AddWindowMenu;
  28.     FUNCTION ItemFromName (theName: Str255): INTEGER;
  29.     PROCEDURE AddWindToMenu (window: WindowPtr);
  30.     PROCEDURE DelWindFromMenu (window: WindowPtr);
  31.  
  32.  
  33.     CONST
  34.         mWindow = 4;          { ID of Window MENU. }
  35.         AEWindItem = 1;
  36.         wholeMenu = 0;
  37.  
  38.     VAR
  39.         WindowMenu: MenuHandle;
  40.         windowName: Str255;
  41.         firstWindowItem: INTEGER;
  42.         textH: TEHandle;
  43.  
  44.  
  45.  
  46.  
  47. IMPLEMENTATION
  48.  
  49.  
  50.  
  51.  
  52.     FUNCTION InitWindowStorage: allWSHdl;
  53. { Call this hummer after "InitManagers". }
  54.  
  55.         VAR
  56.             wsHdl: allWSHdl;
  57.  
  58.  
  59.     BEGIN
  60.  
  61.         InitWindowStorage := NIL;      { Worry-wart !! }
  62.         wsHdl := allWSHdl(NewClearHandle(SizeOf(allWStorage)));
  63.         IF MemError = noErr THEN
  64.         BEGIN
  65.             MoveHHi(Handle(wsHdl));
  66.             HLock(Handle(wsHdl));
  67.             ;
  68.             windowCount := 0;
  69.             newCount := 0;
  70.             InitWindowStorage := wsHdl;
  71.         END;   { IF noErr }
  72.  
  73.     END;   { InitWindowStorage }
  74.  
  75.  
  76.  
  77. { --------------------------------------------------------- }
  78. { CanNOT use the "structRgn" field of the window since this }
  79. { region handle will be NIL if the window is NOT visible.   }
  80. { --------------------------------------------------------- }
  81.  
  82.     PROCEDURE CalcWindowRect (window: WindowPtr; VAR r: Rect);
  83.  
  84.  
  85.     BEGIN
  86.  
  87.         windType := GetWindowType(window);             { In DoActivate, also. }
  88.  
  89.         r := window^.portRect;
  90.         InsetRect(r, -frame, -frame);                  { Include frame. }
  91.         IF (windType = 0) OR (windType > 3) THEN
  92.             r.top := r.top - title;                      { Window has a title bar. }
  93.         IF (windType = documentProc) OR (windType = altDBoxProc) OR (windType = noGrowDocProc) OR (windType = zoomDocProc) THEN
  94.         BEGIN
  95.             r.bottom := r.bottom + shadow;
  96.             r.right := r.right + shadow;
  97.         END;   { Window has a shadow frame. }
  98.  
  99.     END;   { CalcWindowRect }
  100.  
  101.  
  102.  
  103. { --------------------------------------------------- }
  104. { Before showing the window, center it on the screen. }
  105. { --------------------------------------------------- }
  106.  
  107.     FUNCTION GetTLWindPortRect (window: WindowPtr; oldOffset: Point): Point;
  108. { newOffset := GetTLWindPortRect(TheWindow, oldOffset); }
  109.  
  110.         VAR
  111.             wFrameRect: Rect;
  112.             temp: INTEGER;
  113.             PR: Point;
  114.  
  115.     BEGIN
  116.  
  117.         moreNew := TRUE;                               { Assume we can !! }
  118.  
  119.         CalcWindowRect(window, wFrameRect);            { Calls GetWindowType. }
  120.  
  121.         WITH screenBits.bounds DO                     { ... so it doesn't overlap 2nd screen. }
  122.             temp := bottom - top;
  123.         WITH wFrameRect DO
  124.             temp := temp - (bottom - top);               { screen height - window height }
  125.         temp := temp - mBarHt;
  126.         IF temp < 0 THEN
  127.             temp := 0;
  128.         temp := temp DIV 2;
  129.         temp := temp + frame;
  130.         IF (windType = 0) OR (windType > 3) THEN
  131.             temp := temp + title;                        { Window has a title bar. }
  132.         WITH PR, screenBits.bounds DO
  133.         BEGIN
  134.             IF oldOffset.v <> 0 THEN
  135.                 v := oldOffset.v + deltaOffset.v           { From where we were ... }
  136.             ELSE
  137.                 v := top + temp;                           { ... or from scratch.   }
  138.             IF v > (bottom - 2 * deltaOffset.v) THEN
  139.                 moreNew := FALSE;
  140.         END;   { WITH PR, screenBits.bounds }
  141.   { ----- }
  142.         WITH screenBits.bounds DO
  143.             temp := right - left;
  144.         WITH wFrameRect DO
  145.             temp := temp - (right - left);               { screen width - window width }
  146.         IF temp < 0 THEN
  147.             temp := 0;
  148.         WITH PR, screenBits.bounds DO
  149.         BEGIN
  150.             IF oldOffset.h <> 0 THEN
  151.                 h := oldOffset.h + deltaOffset.h
  152.             ELSE
  153.                 h := left + temp DIV 2 + frame;
  154.             IF h > (right - 2 * deltaOffset.h) THEN
  155.                 moreNew := FALSE;
  156.         END;   { WITH PR, screenBits.bounds }
  157.  
  158.         GetTLWindPortRect := PR;
  159.  
  160.     END;   { GetTLWindPortRect }
  161.  
  162.  
  163.  
  164.     PROCEDURE DisplayWindow (window: WindowPtr; TLPR: Point);
  165.  
  166.  
  167.     BEGIN
  168.  
  169.   { The change of TLPR to Global coordinates implemented below is }
  170.   { localized to TLPR passed above since TLPR is not VARed within }
  171.   { "DisplayWindow".  NOTE also that _LocalToGlobal will NOT work }
  172.   { here because "GetTLWindPortRect" returns TLPR in local SCREEN }
  173.   { coordinates and the current port = my window … thus, we'd be  }
  174.   { mixing apples & oranges so-to-speak.                          }
  175.  
  176.         SubPt(screenBits.bounds.topLeft, TLPR);
  177.         ;
  178.         MoveWindow(window, TLPR.h, TLPR.v, TRUE);
  179.         ShowHide(window, TRUE);
  180.  
  181.     END;   { DisplayWindow }
  182.  
  183.  
  184.  
  185.     FUNCTION DoNewWindow (windowID, wMBARID: INTEGER; VAR offset: Point): BOOLEAN;
  186. { IF NOT DoNewWindow( ) THEN }
  187. {  OhOh;                     }
  188.  
  189.         VAR
  190.             i: INTEGER;
  191.             destR, viewR: Rect;
  192.  
  193.         FUNCTION FindWStorage (VAR index: INTEGER): BOOLEAN;
  194.  
  195.         BEGIN
  196.             index := 1;
  197.             WITH windowStorage^^ DO
  198.             BEGIN
  199.                 WHILE (index <= maxWindows) & ones[index].inUse DO
  200.                     index := index + 1;
  201.                 ;
  202.                 IF index <= maxWindows THEN                 { Found one NOT in use. }
  203.                 BEGIN
  204.                     ones[index].inUse := TRUE;
  205.                     FindWStorage := TRUE;
  206.                 END
  207.                 ELSE   { no more windows allowed }
  208.                     FindWStorage := FALSE;
  209.             END;   { WITH }
  210.         END;   { FindWStorage }
  211.  
  212.  
  213.         PROCEDURE SetWindowTitle (window: WindowPtr);
  214.  
  215.             CONST
  216.                 titlePrefix = 'Untitled -';
  217.  
  218.             VAR
  219.                 numString: Str255;
  220.  
  221.         BEGIN
  222.  
  223.             NumToString(newCount, numString);
  224.             SetWTitle(window, concat(titlePrefix, numString));
  225.  
  226.         END;   { SetWindowTitle }
  227.  
  228.  
  229.     BEGIN   { DoNewWindow }
  230.  
  231.         DoNewWindow := FALSE;
  232.         moreNew := moreNew & FindWStorage(i);             { i is VARed. }
  233.         IF NOT moreNew THEN
  234.             EXIT(DoNewWindow);
  235.  
  236.         IF aMac2 THEN
  237.             TheWindow := GetNewCWindow(windowID, @windowStorage^^.ones[i].ws, WindowPtr(-1))
  238.         ELSE
  239.             TheWindow := GetNewWindow(windowID, @windowStorage^^.ones[i].ws, WindowPtr(-1));
  240.         ;
  241.         IF TheWindow = NIL THEN
  242.         BEGIN
  243.             windowStorage^^.ones[i].inUse := FALSE;         { Reverse effect of FindWStorage. }
  244.             EXIT(DoNewWindow);
  245.         END;
  246.         ;
  247.         SetPort(TheWindow);
  248.  
  249.         mBar := wGetNewMBar(TheWindow, wMBARID);
  250.         IF mBar <> NIL THEN
  251.             wAddWMB(mBar);
  252.  
  253.         IF windowID = newWindowID THEN
  254.         BEGIN
  255.             newCount := newCount + 1;
  256.             SetWindowTitle(TheWindow);
  257.             ourControl := GetNewControl(horizScrollID, TheWindow);
  258.             ourControl := GetNewControl(vertScrollID, TheWindow);
  259.             ;
  260.             WITH TheWindow^.portRect DO
  261.                 SetRect(viewR, 0, 0, right - (scrollWidth - 1), bottom - (scrollHeight - 1));
  262.             IF mBar <> NIL THEN
  263.                 viewR.top := viewR.top + mBarHt;
  264.             destR := viewR;
  265.             InsetRect(destR, 4, 4);
  266.             ;
  267.             textH := TENew(destR, viewR);
  268.             SetWRefCon(TheWindow, LONGINT(textH));
  269.         END   { newWindowID }
  270.         ELSE
  271.             SetWRefCon(TheWindow, 0);   { rDocProc }
  272.  
  273.         offset := GetTLWindPortRect(TheWindow, offset);   { oldOffset --> newOffset }
  274.  
  275.         ScrollResize(TheWindow);                          { Does nada if NO Scroll Bars. }
  276.         DisplayWindow(TheWindow, offset);
  277.  
  278.   { Since an Update Event draws the MSAs & the Window Menu Bar, }
  279.   { we do NOT want these drawn by the DoActivate PROC:          }
  280.         brandNew := TRUE;
  281.  
  282.         windowCount := windowCount + 1;
  283.         moreNew := moreNew & (windowCount < maxWindows);
  284.         DoNewWindow := TRUE;
  285.         ;
  286.         AddWindToMenu(TheWindow);
  287.  
  288.     END;   { DoNewWindow }
  289.  
  290.  
  291.  
  292. { ----------------------- }
  293. { One at a time, folks !! }
  294. { ----------------------- }
  295.  
  296.     PROCEDURE CloseOurWindow (window: WindowPtr);
  297.  
  298.         VAR
  299.             myPic: PicHandle;
  300.             pal: PaletteHandle;
  301.             aux: BOOLEAN;
  302.             auxWind: AuxWinHndl;
  303.  
  304.         PROCEDURE DisposeWStorage (wp: WindowPtr);
  305.  
  306.             VAR
  307.                 i: INTEGER;
  308.                 found: BOOLEAN;
  309.                 wsHState: SignedByte;
  310.  
  311.         BEGIN
  312.  
  313.             found := FALSE;
  314.  
  315.     { On input to this PROC, the windowStorage Handle is locked.  }
  316.     { "IF wp = @ones[i].ws" below creates a Pointer to a field    }
  317.     { in this locked Master Pointer.  Therefore, the former is    }
  318.     { also locked, with Bit #31 set.  But the passed WindowPtr    }
  319.     { is NOT locked and, therefore, its Bit #31 is clear.  So ... }
  320.     {                                                             }
  321.     { oneWStorage  dsec  0                                        }
  322.     { inUse        byte                  ; = 0                    }
  323.     { fill         byte                  ; = 1                    }
  324.     { ws           byte  WindowSize      ; = 2                    }
  325.     {              dend                                           }
  326.     {              ...                                            }
  327.     {              move.l  windowStorage,a0                       }
  328.     {              move.l  (a0),a4       ; Locked Master Pointer. }
  329.     {              lea     ws(a4),a1     ; Bit #31 also set.      }
  330.     {              cmpa.l  wp,a1         ; wp = 8(a6)             }
  331.     {              ...                                            }
  332.  
  333.             wsHState := HGetState(Handle(windowStorage));
  334.             windowStorage^ := allWSPtr(QuickStrip(Ptr(windowStorage^)));
  335.             WITH windowStorage^^ DO
  336.             BEGIN
  337.                 FOR i := 1 TO maxWindows DO
  338.                     IF ones[i].inUse THEN
  339.                         IF wp = @ones[i].ws THEN
  340.                         BEGIN
  341.                             found := TRUE;
  342.                             Leave;
  343.                         END;
  344.                 IF found THEN
  345.                     ones[i].inUse := FALSE          { Undo effect of FindWStorage. }
  346.                 ELSE   { should NOT happen !! }
  347.                     ;
  348.             END;   { WITH }
  349.             ;
  350.     { We have NOT done anything to move memory, }
  351.     { therefore _MoveHHi is NOT required.       }
  352.             HSetState(Handle(windowStorage), wsHState);
  353.  
  354.         END;   { DisposeWStorage }
  355.  
  356.  
  357.     BEGIN   { CloseOurWindow }
  358.  
  359.         IF window = NIL THEN
  360.             EXIT(CloseOurWindow);
  361.  
  362.         IF WindowPeek(window)^.windowKind < 0 THEN
  363.             CloseDeskAcc(WindowPeek(window)^.windowKind)
  364.         ELSE
  365.         BEGIN
  366.             IF aMac2 THEN
  367.             BEGIN
  368.                 pal := GetPalette(window);
  369.                 IF pal <> NIL THEN
  370.                     DisposePalette(pal);
  371.             END;   { IF aMac2 }
  372.  
  373.             myPic := GetWindowPic(window);
  374.             IF myPic <> NIL THEN
  375.             BEGIN
  376.                 HUnlock(Handle(myPic));
  377.                 ReleaseResource(Handle(myPic));
  378.             END;   { IF myPic <> NIL }
  379.  
  380.             textH := TEHandle(GetWRefCon(window));
  381.             IF textH <> NIL THEN
  382.                 TEDispose(textH);
  383.  
  384.             wDeleteWMB(window);
  385.             DelWindFromMenu(window);
  386.             DisposeWStorage(window);
  387.             CloseWindow(window);
  388.  
  389.             WITH offset DO
  390.             BEGIN
  391.                 h := h - deltaOffset.h;
  392.                 IF h < 0 THEN
  393.                     h := 0;
  394.                 v := v - deltaOffset.v;
  395.                 IF v < 0 THEN
  396.                     v := 0;
  397.             END;   { WITH }
  398.  
  399.             windowCount := windowCount - 1;
  400.             IF windowCount = 0 THEN
  401.             BEGIN
  402.       { In case a lingering DA doesn't properly handle its "doCursor" routine: }
  403.                 InitCursor;
  404.       { Wait till last is gone because all windows share a common Color Table. }
  405.                 IF aMac2 THEN
  406.                 BEGIN
  407.                     aux := GetAuxWin(window, auxWind);
  408.                     IF aux THEN
  409.                         ReleaseResource(Handle(auxWind));
  410.                 END;   { IF aMac2 }
  411.             END;   { IF no more windows }
  412.  
  413.             moreNew := TRUE;
  414.         END;   { NOT a Desk Accessory window }
  415.  
  416.     END;   { CloseOurWindow }
  417.  
  418.  
  419.  
  420. { ----------------------------------------------------------- }
  421. { DoCloseAll is called from within "DoQuit".  Note that we    }
  422. { close windows from back to front by calling CloseBehind     }
  423. { recursively.  In this manner, window updating is minimized. }
  424. { Reference: APDA's "Programmer's Guide to MultiFinder" [B-5] }
  425. { ----------------------------------------------------------- }
  426.  
  427.     PROCEDURE DoCloseAll;
  428.  
  429.         PROCEDURE CloseBehind (window: WindowPtr);
  430.         BEGIN
  431.             IF window <> NIL THEN
  432.             BEGIN
  433.                 CloseBehind(WindowPtr(WindowPeek(window)^.nextWindow));
  434.                 CloseOurWindow(window);
  435.             END;   { IF }
  436.         END;   { CloseBehind }
  437.  
  438.  
  439.     BEGIN
  440.         CloseBehind(FrontWindow);
  441.     END;   { DoCloseAll }
  442.  
  443.  
  444.  
  445.     PROCEDURE UncheckOldItem (windMenu: MenuHandle);
  446.  
  447.         VAR
  448.             whichItem: INTEGER;
  449.             markChar: Char;
  450.  
  451.  
  452.     BEGIN
  453.  
  454.         FOR whichItem := firstWindowItem TO CountMItems(windMenu) DO
  455.         BEGIN
  456.             GetItemMark(windMenu, whichItem, markChar);
  457.             IF markChar <> chr(0) THEN
  458.             BEGIN
  459.                 CheckItem(windMenu, whichItem, false);
  460.                 Leave;   { FOR loop }
  461.             END;   { IF }
  462.         END;   { FOR }
  463.  
  464.     END;   { UncheckOldItem }
  465.  
  466.  
  467.  
  468.     PROCEDURE AddWindowMenu;
  469.  
  470.     BEGIN
  471.  
  472.         WindowMenu := NewMenu(mWindow, 'Windows');
  473.  
  474.         IF WindowMenu <> NIL THEN
  475.         BEGIN
  476.             InsertMenu(WindowMenu, 0);
  477.             ;
  478.             IF gInitAppleEvents = noErr THEN
  479.             BEGIN
  480.                 AppendMenu(WindowMenu, 'Send “Move Window” AppleEvent<I/M');
  481.                 AppendMenu(WindowMenu, '(-');
  482.                 firstWindowItem := 5;     { After the "Next window" item. }
  483.             END
  484.             ELSE
  485.                 firstWindowItem := 3;
  486.             ;
  487.             AppendMenu(WindowMenu, '(Next window/,');
  488.             AppendMenu(WindowMenu, '(-');
  489.         END;   { WindowMenu <> NIL }
  490.  
  491.     END;   { AddWindowMenu }
  492.  
  493.  
  494.  
  495.     FUNCTION ItemFromName (theName: Str255): INTEGER;
  496.  
  497.         VAR
  498.             itemString: Str255;
  499.             whichItem: INTEGER;
  500.  
  501.  
  502.     BEGIN
  503.  
  504.         FOR whichItem := firstWindowItem TO CountMItems(WindowMenu) DO
  505.         BEGIN
  506.             GetItem(WindowMenu, whichItem, itemString);
  507.             IF itemString = theName THEN
  508.                 Leave;   { FOR loop }
  509.         END;
  510.  
  511.         ItemFromName := whichItem;     { = CountMItems() +1 if NOT found. }
  512.  
  513.     END;   { ItemFromName }
  514.  
  515.  
  516.  
  517.     PROCEDURE AddWindToMenu (window: WindowPtr);
  518.  
  519.         VAR
  520.             item: INTEGER;
  521.  
  522.  
  523.     BEGIN
  524.  
  525.         item := CountMItems(WindowMenu);
  526.         UncheckOldItem(WindowMenu);                 { Un-check the old one ... }
  527.         GetWTitle(window, windowName);
  528.         InsMenuItem(WindowMenu, windowName, item);
  529.         CheckItem(WindowMenu, item + 1, true);      { & check the new one.     }
  530.  
  531.     END;   { AddWindToMenu }
  532.  
  533.  
  534.  
  535.     PROCEDURE DelWindFromMenu (window: WindowPtr);
  536.  
  537.         VAR
  538.             itemString, wpTitle: Str255;
  539.             wPeek: WindowPeek;
  540.  
  541.  
  542.     BEGIN
  543.  
  544.         GetWTitle(window, windowName);
  545.         DelMenuItem(WindowMenu, ItemFromName(windowName));
  546.         wPeek := WindowPeek(FrontWindow)^.nextWindow;
  547.         IF (wPeek <> NIL) & (wPeek^.windowKind = userKind) THEN
  548.         BEGIN
  549.             wpTitle := wPeek^.titleHandle^^;
  550.             CheckItem(WindowMenu, ItemFromName(wpTitle), true);    { Check the one in back. }
  551.         END;
  552.  
  553.     END;   { DelWindFromMenu }
  554.  
  555.  
  556.  
  557.  
  558. END.   { UNIT = wBMWindSubs }